package com.baomidou.mybatisplus.samples.tenant.config;

import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.baomidou.mybatisplus.samples.tenant.handler.PlusTenantLineHandler;
import com.baomidou.mybatisplus.samples.tenant.interceptor.PlusTenantLineInnerInterceptor;
import com.baomidou.mybatisplus.samples.tenant.properties.TenantProperties;
import lombok.RequiredArgsConstructor;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;

import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;

/**
 * @author miemie
 * @since 2018-08-10
 */
@Configuration
@MapperScan("com.baomidou.mybatisplus.samples.tenant.mapper")
@RequiredArgsConstructor
public class MybatisPlusConfig {
    private final TenantProperties properties;


    /**
     * 新多租户插件配置,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存万一出现问题
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(tenantInnerInterceptor());

        // 如果用了分页插件注意先 add TenantLineInnerInterceptor 再 add PaginationInnerInterceptor
        // 用了分页插件必须设置 MybatisConfiguration#useDeprecatedExecutor = false
//        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }

//    @Bean
//    public ConfigurationCustomizer configurationCustomizer() {
//        return configuration -> configuration.setUseDeprecatedExecutor(false);
//    }

    /**
     * 租户拦截器
     */
    private InnerInterceptor tenantInnerInterceptor() {
        return new  PlusTenantLineInnerInterceptor(

                new PlusTenantLineHandler() {
                    /**
                     * 查询时，设置的租户值, 可以设置多个指。如 select xxx tenant_id in (8888, 1)
                     */
                    @Override
                    public ItemsList selectTenantId() {
                        // TODO 根据业务需求获取租户id
//                return new ExpressionList(new LongValue(888), new LongValue(0), new LongValue(1));
                        final StringValue[] ids = TenantContext.getTenantIds().stream().map(id -> new StringValue(id)).toArray(StringValue[]::new);
                        return new ExpressionList(ids);
                    }


                    /**
                     * 插入更新数据时，设置的租户值, 如： update user set is_delete = 0 where tenant_id = xxxxx
                     */
                    @Override
                    public Expression insertTenantId() {
                        // TODO 根据业务需求获取租户id
                        return new LongValue(666);
                    }


                    /**
                     * 指定租户字段名
                     * <p>
                     * 默认字段名叫: tenant_id
                     */
                    @Override
                    public String getTenantIdColumn() {
                        return properties.getColumn();
                    }

                    /**
                     * 根据表名判断是否忽略拼接多租户条件
                     *
                     * 默认都解析多租户条件
                     * @param tableName 表名
                     * @return 是否忽略, true:表示忽略，false:需要解析并拼接多租户条件
                     */
                    @Override
                    public boolean ignoreTable(String tableName) {
                        return properties.getExclusionTable().stream().anyMatch(e -> tableName.equals(e));
                    }

                    /**
                     * 是否忽略租户查询
                     */
                    @Override
                    public Boolean ignore(String method) {
                        // 关闭租户功能或在方法上使用了@IgnoreTenant都忽略租户条件
                        return !properties.getEnable()|| TenantContext.getIgnore();
                    }
                }

        );
    }

}
